9 關注者

資料庫遷移

在開發和維護資料庫驅動的應用程式的過程中,所使用資料庫的結構會像原始碼一樣演進。例如,在應用程式的開發過程中,可能會發現需要一個新的表格;在應用程式部署到生產環境後,可能會發現應該建立索引以提高查詢效能;等等。由於資料庫結構變更通常需要一些原始碼變更,Yii 支援所謂的資料庫遷移功能,讓您可以根據資料庫遷移來追蹤資料庫變更,這些遷移會與原始碼一起進行版本控制。

以下步驟顯示團隊在開發期間如何使用資料庫遷移

  1. Tim 建立新的遷移(例如,建立新的表格、變更欄位定義等)。
  2. Tim 將新的遷移提交到原始碼控制系統(例如 Git、Mercurial)。
  3. Doug 從原始碼控制系統更新他的儲存庫,並接收新的遷移。
  4. Doug 將遷移套用到他的本機開發資料庫,從而同步他的資料庫以反映 Tim 所做的變更。

以下步驟顯示如何將包含資料庫遷移的新版本部署到生產環境

  1. Scott 為專案儲存庫建立一個包含一些新的資料庫遷移的版本標籤。
  2. Scott 將生產伺服器上的原始碼更新到版本標籤。
  3. Scott 將任何累積的資料庫遷移套用到生產資料庫。

Yii 提供了一組遷移命令列工具,讓您可以

  • 建立新的遷移;
  • 套用遷移;
  • 還原遷移;
  • 重新套用遷移;
  • 顯示遷移歷史和狀態。

所有這些工具都可以透過命令 yii migrate 存取。在本節中,我們將詳細描述如何使用這些工具完成各種任務。您也可以透過 help 命令 yii help migrate 取得每個工具的用法。

提示:遷移不僅可能影響資料庫結構描述,還可能調整現有資料以符合新的結構描述、建立 RBAC 層次結構或清除快取。

注意:當使用遷移操作資料時,您可能會發現使用您的 Active Record 類別很有用,因為某些邏輯已經在那裡實現了。但是請記住,與寫在遷移中的程式碼(其本質是永遠保持不變)相反,應用程式邏輯可能會發生變化。因此,當在遷移程式碼中使用 Active Record 時,對 Active Record 層中的邏輯的變更可能會意外地破壞現有的遷移。因此,遷移程式碼應保持獨立於其他應用程式邏輯,例如 Active Record 類別。

建立遷移

若要建立新的遷移,請執行以下命令

yii migrate/create <name>

必要的 name 引數提供有關新遷移的簡要描述。例如,如果遷移是關於建立名為 news 的新表格,您可以使用名稱 create_news_table 並執行以下命令

yii migrate/create create_news_table

注意:由於 name 引數將用作產生的遷移類別名稱的一部分,因此它應僅包含字母、數字和/或底線字元。

上面的命令將在 @app/migrations 目錄中建立一個名為 m150101_185401_create_news_table.php 的新 PHP 類別檔案。該檔案包含以下程式碼,該程式碼主要宣告一個遷移類別 m150101_185401_create_news_table,其中包含骨架程式碼

<?php

use yii\db\Migration;

class m150101_185401_create_news_table extends Migration
{
    public function up()
    {

    }

    public function down()
    {
        echo "m101129_185401_create_news_table cannot be reverted.\n";

        return false;
    }

    /*
    // Use safeUp/safeDown to run migration code within a transaction
    public function safeUp()
    {
    }

    public function safeDown()
    {
    }
    */
}

每個資料庫遷移都定義為從 yii\db\Migration 擴展的 PHP 類別。遷移類別名稱會自動以 m<YYMMDD_HHMMSS>_<Name> 格式產生,其中

  • <YYMMDD_HHMMSS> 是指執行遷移建立命令時的 UTC 日期時間。
  • <Name> 與您提供給命令的 name 引數的值相同。

在遷移類別中,您應該在 up() 方法中編寫程式碼,以變更資料庫結構。您可能還想在 down() 方法中編寫程式碼,以還原 up() 所做的變更。當您使用此遷移升級資料庫時,會調用 up() 方法,而當您降級資料庫時,會調用 down() 方法。以下程式碼顯示您如何實作遷移類別以建立 news 表格

<?php

use yii\db\Schema;
use yii\db\Migration;

class m150101_185401_create_news_table extends Migration
{
    public function up()
    {
        $this->createTable('news', [
            'id' => Schema::TYPE_PK,
            'title' => Schema::TYPE_STRING . ' NOT NULL',
            'content' => Schema::TYPE_TEXT,
        ]);
    }

    public function down()
    {
        $this->dropTable('news');
    }
}

資訊:並非所有遷移都是可逆的。例如,如果 up() 方法刪除表格的一列,您可能無法在 down() 方法中恢復此列。有時,您可能只是懶得實作 down(),因為還原資料庫遷移並不常見。在這種情況下,您應該在 down() 方法中傳回 false,以指示遷移不可逆。

基礎遷移類別 yii\db\Migration 透過 db 屬性公開資料庫連線。您可以使用它來操作資料庫結構描述,方法如 使用資料庫結構描述 中所述。

在建立表格或欄位時,您應該使用抽象類型,而不是使用實體類型,以便您的遷移獨立於特定的 DBMS。yii\db\Schema 類別定義了一組常數來表示支援的抽象類型。這些常數的命名格式為 TYPE_<Name>。例如,TYPE_PK 指的是自動遞增主鍵類型;TYPE_STRING 指的是字串類型。當遷移套用到特定資料庫時,抽象類型將轉換為相應的實體類型。在 MySQL 的情況下,TYPE_PK 將轉換為 int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,而 TYPE_STRING 則變為 varchar(255)

您可以在使用抽象類型時附加其他約束。在上面的範例中, NOT NULL 附加到 Schema::TYPE_STRING,以指定欄位不能為 null

資訊:抽象類型和實體類型之間的對應關係由每個具體的 QueryBuilder 類別中的 $typeMap 屬性指定。

自 2.0.6 版起,您可以利用新引入的結構描述建構器,它提供了更方便的方式來定義欄位結構描述。因此,上面的遷移可以像下面這樣編寫

<?php

use yii\db\Migration;

class m150101_185401_create_news_table extends Migration
{
    public function up()
    {
        $this->createTable('news', [
            'id' => $this->primaryKey(),
            'title' => $this->string()->notNull(),
            'content' => $this->text(),
        ]);
    }

    public function down()
    {
        $this->dropTable('news');
    }
}

可用於定義欄位類型的所有方法的列表可在 yii\db\SchemaBuilderTrait 的 API 文件中找到。

資訊:產生的檔案權限和所有權將由目前環境決定。這可能會導致無法存取的檔案。例如,當遷移在 Docker 容器中建立,而檔案在主機上編輯時,可能會發生這種情況。在這種情況下,可以變更 MigrateController 的 newFileMode 和/或 newFileOwnership。例如,在應用程式組態中: `php <?php return [

  'controllerMap' => [
      'migrate' => [
          'class' => 'yii\console\controllers\MigrateController',
          'newFileOwnership' => '1000:1000', # Default WSL user id
          'newFileMode' => 0660,
      ],
  ],

]; `

產生遷移

自 2.0.7 版起,遷移主控台提供了一種方便的方式來建立遷移。

如果遷移名稱採用特殊形式,例如 create_xxx_tabledrop_xxx_table,則產生的遷移檔案將包含額外的程式碼,在這種情況下用於建立/刪除表格。以下描述了此功能的所有變體。

建立表格

yii migrate/create create_post_table

產生

/**
 * Handles the creation for table `post`.
 */
class m150811_220037_create_post_table extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function up()
    {
        $this->createTable('post', [
            'id' => $this->primaryKey()
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function down()
    {
        $this->dropTable('post');
    }
}

若要立即建立表格欄位,請透過 --fields 選項指定它們。

yii migrate/create create_post_table --fields="title:string,body:text"

產生

/**
 * Handles the creation for table `post`.
 */
class m150811_220037_create_post_table extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function up()
    {
        $this->createTable('post', [
            'id' => $this->primaryKey(),
            'title' => $this->string(),
            'body' => $this->text(),
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function down()
    {
        $this->dropTable('post');
    }
}

您可以指定更多欄位參數。

yii migrate/create create_post_table --fields="title:string(12):notNull:unique,body:text"

產生

/**
 * Handles the creation for table `post`.
 */
class m150811_220037_create_post_table extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function up()
    {
        $this->createTable('post', [
            'id' => $this->primaryKey(),
            'title' => $this->string(12)->notNull()->unique(),
            'body' => $this->text()
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function down()
    {
        $this->dropTable('post');
    }
}

注意:主鍵會自動新增,預設名稱為 id。如果您想使用另一個名稱,可以明確指定它,例如 --fields="name:primaryKey"

外鍵

自 2.0.8 起,產生器支援使用 foreignKey 關鍵字的外鍵。

yii migrate/create create_post_table --fields="author_id:integer:notNull:foreignKey(user),category_id:integer:defaultValue(1):foreignKey,title:string,body:text"

產生

/**
 * Handles the creation for table `post`.
 * Has foreign keys to the tables:
 *
 * - `user`
 * - `category`
 */
class m160328_040430_create_post_table extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function up()
    {
        $this->createTable('post', [
            'id' => $this->primaryKey(),
            'author_id' => $this->integer()->notNull(),
            'category_id' => $this->integer()->defaultValue(1),
            'title' => $this->string(),
            'body' => $this->text(),
        ]);

        // creates index for column `author_id`
        $this->createIndex(
            'idx-post-author_id',
            'post',
            'author_id'
        );

        // add foreign key for table `user`
        $this->addForeignKey(
            'fk-post-author_id',
            'post',
            'author_id',
            'user',
            'id',
            'CASCADE'
        );

        // creates index for column `category_id`
        $this->createIndex(
            'idx-post-category_id',
            'post',
            'category_id'
        );

        // add foreign key for table `category`
        $this->addForeignKey(
            'fk-post-category_id',
            'post',
            'category_id',
            'category',
            'id',
            'CASCADE'
        );
    }

    /**
     * {@inheritdoc}
     */
    public function down()
    {
        // drops foreign key for table `user`
        $this->dropForeignKey(
            'fk-post-author_id',
            'post'
        );

        // drops index for column `author_id`
        $this->dropIndex(
            'idx-post-author_id',
            'post'
        );

        // drops foreign key for table `category`
        $this->dropForeignKey(
            'fk-post-category_id',
            'post'
        );

        // drops index for column `category_id`
        $this->dropIndex(
            'idx-post-category_id',
            'post'
        );

        $this->dropTable('post');
    }
}

foreignKey 關鍵字在欄位描述中的位置不會變更產生的程式碼。這表示

  • author_id:integer:notNull:foreignKey(user)
  • author_id:integer:foreignKey(user):notNull
  • author_id:foreignKey(user):integer:notNull

全部產生相同的程式碼。

foreignKey 關鍵字可以接受括號之間的參數,該參數將作為產生的外鍵的相關表格的名稱。如果未傳遞任何參數,則表格名稱將從欄位名稱中推斷出來。

在上面的範例中,author_id:integer:notNull:foreignKey(user) 將產生一個名為 author_id 的欄位,其中包含指向 user 表格的外鍵,而 category_id:integer:defaultValue(1):foreignKey 將產生一個欄位 category_id,其中包含指向 category 表格的外鍵。

自 2.0.11 起,foreignKey 關鍵字接受第二個參數,以空格分隔。它接受產生的外鍵的相關欄位名稱。如果未傳遞第二個參數,則將從表格結構描述中提取欄位名稱。如果不存在結構描述,則未設定主鍵或為主鍵或複合主鍵,將使用預設名稱 id

刪除表格

yii migrate/create drop_post_table --fields="title:string(12):notNull:unique,body:text"

產生

class m150811_220037_drop_post_table extends Migration
{
    public function up()
    {
        $this->dropTable('post');
    }

    public function down()
    {
        $this->createTable('post', [
            'id' => $this->primaryKey(),
            'title' => $this->string(12)->notNull()->unique(),
            'body' => $this->text()
        ]);
    }
}

新增欄位

如果遷移名稱的形式為 add_xxx_column_to_yyy_table,則檔案內容將包含必要的 addColumndropColumn 陳述式。

若要新增欄位

yii migrate/create add_position_column_to_post_table --fields="position:integer"

產生

class m150811_220037_add_position_column_to_post_table extends Migration
{
    public function up()
    {
        $this->addColumn('post', 'position', $this->integer());
    }

    public function down()
    {
        $this->dropColumn('post', 'position');
    }
}

您可以如下指定多個欄位

yii migrate/create add_xxx_column_yyy_column_to_zzz_table --fields="xxx:integer,yyy:text"

刪除欄位

如果遷移名稱的形式為 drop_xxx_column_from_yyy_table,則檔案內容將包含必要的 addColumndropColumn 陳述式。

yii migrate/create drop_position_column_from_post_table --fields="position:integer"

產生

class m150811_220037_drop_position_column_from_post_table extends Migration
{
    public function up()
    {
        $this->dropColumn('post', 'position');
    }

    public function down()
    {
        $this->addColumn('post', 'position', $this->integer());
    }
}

新增連接表格

如果遷移名稱的形式為 create_junction_table_for_xxx_and_yyy_tablescreate_junction_xxx_and_yyy_tables,則將產生建立連接表格所需的程式碼。

yii migrate/create create_junction_table_for_post_and_tag_tables --fields="created_at:dateTime"

產生

/**
 * Handles the creation for table `post_tag`.
 * Has foreign keys to the tables:
 *
 * - `post`
 * - `tag`
 */
class m160328_041642_create_junction_table_for_post_and_tag_tables extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function up()
    {
        $this->createTable('post_tag', [
            'post_id' => $this->integer(),
            'tag_id' => $this->integer(),
            'created_at' => $this->dateTime(),
            'PRIMARY KEY(post_id, tag_id)',
        ]);

        // creates index for column `post_id`
        $this->createIndex(
            'idx-post_tag-post_id',
            'post_tag',
            'post_id'
        );

        // add foreign key for table `post`
        $this->addForeignKey(
            'fk-post_tag-post_id',
            'post_tag',
            'post_id',
            'post',
            'id',
            'CASCADE'
        );

        // creates index for column `tag_id`
        $this->createIndex(
            'idx-post_tag-tag_id',
            'post_tag',
            'tag_id'
        );

        // add foreign key for table `tag`
        $this->addForeignKey(
            'fk-post_tag-tag_id',
            'post_tag',
            'tag_id',
            'tag',
            'id',
            'CASCADE'
        );
    }

    /**
     * {@inheritdoc}
     */
    public function down()
    {
        // drops foreign key for table `post`
        $this->dropForeignKey(
            'fk-post_tag-post_id',
            'post_tag'
        );

        // drops index for column `post_id`
        $this->dropIndex(
            'idx-post_tag-post_id',
            'post_tag'
        );

        // drops foreign key for table `tag`
        $this->dropForeignKey(
            'fk-post_tag-tag_id',
            'post_tag'
        );

        // drops index for column `tag_id`
        $this->dropIndex(
            'idx-post_tag-tag_id',
            'post_tag'
        );

        $this->dropTable('post_tag');
    }
}

自 2.0.11 起,連接表格的外鍵欄位名稱是從表格結構描述中提取的。如果表格未在結構描述中定義,或者未設定主鍵或為主鍵或複合主鍵,則使用預設名稱 id

事務性遷移

在執行複雜的資料庫遷移時,務必確保每個遷移都能完全成功或失敗,以便資料庫可以保持完整性和一致性。為了實現此目標,建議您將每個遷移的資料庫操作封閉在 事務 中。

實作事務性遷移的更簡單方法是將遷移程式碼放在 safeUp()safeDown() 方法中。這兩個方法與 up()down() 的不同之處在於它們隱式地封閉在事務中。因此,如果這些方法中的任何操作失敗,所有先前的操作都將自動回滾。

在以下範例中,除了建立 news 表格外,我們還在此表格中插入初始列。

<?php

use yii\db\Migration;

class m150101_185401_create_news_table extends Migration
{
    public function safeUp()
    {
        $this->createTable('news', [
            'id' => $this->primaryKey(),
            'title' => $this->string()->notNull(),
            'content' => $this->text(),
        ]);

        $this->insert('news', [
            'title' => 'test 1',
            'content' => 'content 1',
        ]);
    }

    public function safeDown()
    {
        $this->delete('news', ['id' => 1]);
        $this->dropTable('news');
    }
}

請注意,通常當您在 safeUp() 中執行多個資料庫操作時,您應該在 safeDown() 中反轉它們的執行順序。在上面的範例中,我們首先建立表格,然後在 safeUp() 中插入一列;而在 safeDown() 中,我們首先刪除該列,然後刪除表格。

注意:並非所有 DBMS 都支援事務。並且某些資料庫查詢無法放入事務中。有關一些範例,請參閱 隱式提交。如果是這種情況,您仍然應該實作 up()down(),而不是 safeUp()safeDown()

資料庫存取方法

基礎遷移類別 yii\db\Migration 提供了一組方法,讓您可以存取和操作資料庫。您可能會發現這些方法的命名與 yii\db\Command 類別提供的 DAO 方法 類似。例如,yii\db\Migration::createTable() 方法可讓您建立新的表格,就像 yii\db\Command::createTable() 一樣。

使用 yii\db\Migration 提供的方法的好處是,您不需要顯式建立 yii\db\Command 實例,並且每個方法的執行都會自動顯示有用的訊息,告訴您完成了哪些資料庫操作以及它們花費了多長時間。

以下是所有這些資料庫存取方法的列表

資訊:yii\db\Migration 不提供資料庫查詢方法。這是因為您通常不需要顯示有關從資料庫檢索資料的額外訊息。這也是因為您可以使用強大的 查詢建構器 來建立和執行複雜的查詢。在遷移中使用查詢建構器可能如下所示

// update status field for all users
foreach((new Query)->from('users')->each() as $user) {
    $this->update('users', ['status' => 1], ['id' => $user['id']]);
}

套用遷移

若要將資料庫升級到其最新結構,您應該使用以下命令套用所有可用的新遷移

yii migrate

此命令將列出所有尚未套用的遷移。如果您確認要套用這些遷移,它將依序執行每個新遷移類別中的 up()safeUp() 方法,依時間戳記值排序。如果任何遷移失敗,命令將退出,而不會套用其餘的遷移。

提示:如果您在伺服器上沒有命令列,您可以嘗試 web shell 擴展。

對於每個已成功套用的遷移,命令將在名為 migration 的資料庫表格中插入一列,以記錄遷移的成功套用。這將允許遷移工具識別哪些遷移已套用,哪些尚未套用。

資訊:遷移工具將在命令的 db 選項指定的資料庫中自動建立 migration 表格。預設情況下,資料庫由 db 應用程式元件 指定。

有時,您可能只想套用一個或幾個新的遷移,而不是所有可用的遷移。您可以透過在執行命令時指定您要套用的遷移數量來做到這一點。例如,以下命令將嘗試套用接下來三個可用的遷移

yii migrate 3

您也可以使用以下格式之一的 migrate/to 命令明確指定資料庫應遷移到的特定遷移

yii migrate/to 150101_185401                      # using timestamp to specify the migration
yii migrate/to "2015-01-01 18:54:01"              # using a string that can be parsed by strtotime()
yii migrate/to m150101_185401_create_news_table   # using full name
yii migrate/to 1392853618                         # using UNIX timestamp

如果指定的遷移之前有任何未套用的遷移,則它們將在套用指定的遷移之前全部套用。

如果指定的遷移之前已套用,則任何稍後套用的遷移都將被還原。

還原遷移

若要還原(撤銷)一個或多個先前已套用的遷移,您可以執行以下命令

yii migrate/down     # revert the most recently applied migration
yii migrate/down 3   # revert the most 3 recently applied migrations

注意:並非所有遷移都是可逆的。嘗試還原此類遷移將導致錯誤並停止整個還原過程。

重做遷移

重做遷移表示首先還原指定的遷移,然後再次套用。這可以如下完成

yii migrate/redo        # redo the last applied migration
yii migrate/redo 3      # redo the last 3 applied migrations

注意:如果遷移不可逆,您將無法重做它。

刷新遷移

自 Yii 2.0.13 起,您可以從資料庫中刪除所有表格和外鍵,並從頭開始套用所有遷移。

yii migrate/fresh       # truncate the database and apply all migrations from the beginning

列出遷移

若要列出哪些遷移已套用以及哪些尚未套用,您可以使用以下命令

yii migrate/history     # showing the last 10 applied migrations
yii migrate/history 5   # showing the last 5 applied migrations
yii migrate/history all # showing all applied migrations

yii migrate/new         # showing the first 10 new migrations
yii migrate/new 5       # showing the first 5 new migrations
yii migrate/new all     # showing all new migrations

修改遷移歷史

有時,您可能只想標記您的資料庫已升級到特定遷移,而不是實際套用或還原遷移。當您手動將資料庫變更為特定狀態,並且不希望稍後重新套用該變更的遷移時,通常會發生這種情況。您可以使用以下命令實現此目標

yii migrate/mark 150101_185401                      # using timestamp to specify the migration
yii migrate/mark "2015-01-01 18:54:01"              # using a string that can be parsed by strtotime()
yii migrate/mark m150101_185401_create_news_table   # using full name
yii migrate/mark 1392853618                         # using UNIX timestamp

該命令將修改 migration 表格,透過新增或刪除某些列來指示資料庫已套用遷移到指定的遷移。此命令不會套用或還原任何遷移。

自訂遷移

有多種方法可以自訂遷移命令。

使用命令列選項

遷移命令帶有一些命令列選項,可用於自訂其行為

  • interactive:布林值(預設為 true),指定是否以互動模式執行遷移。當此值為 true 時,在命令執行某些操作之前,將提示使用者。如果命令在背景程序中使用,您可能希望將其設定為 false

  • migrationPath:字串|陣列(預設為 @app/migrations),指定儲存所有遷移類別檔案的目錄。這可以指定為目錄路徑或路徑 別名。請注意,目錄必須存在,否則命令可能會觸發錯誤。自 2.0.12 版起,可以指定陣列以從多個來源載入遷移。

  • migrationTable:字串(預設為 migration),指定用於儲存遷移歷史資訊的資料庫表格的名稱。如果表格不存在,則命令將自動建立表格。您也可以使用結構 version varchar(255) primary key, apply_time integer 手動建立它。

  • db:字串(預設為 db),指定資料庫 應用程式元件 的 ID。它表示將使用此命令遷移的資料庫。

  • templateFile:字串(預設為 @yii/views/migration.php),指定用於產生骨架遷移類別檔案的範本檔案的路徑。這可以指定為檔案路徑或路徑 別名。範本檔案是一個 PHP 腳本,您可以在其中使用名為 $className 的預定義變數來取得遷移類別名稱。

  • generatorTemplateFiles:陣列(預設為 `[

      'create_table' => '@yii/views/createTableMigration.php',
      'drop_table' => '@yii/views/dropTableMigration.php',
      'add_column' => '@yii/views/addColumnMigration.php',
      'drop_column' => '@yii/views/dropColumnMigration.php',
      'create_junction' => '@yii/views/createTableMigration.php'
    

    ]`),指定用於產生遷移程式碼的範本檔案。請參閱「產生遷移」以取得更多詳細資訊。

  • fields:用於建立遷移程式碼的欄位定義字串陣列。預設值為 []。每個定義的格式為 COLUMN_NAME:COLUMN_TYPE:COLUMN_DECORATOR。例如,--fields=name:string(12):notNull 會產生一個大小為 12 且不可為 null 的字串欄位。

以下範例展示如何使用這些選項。

例如,如果我們想要遷移一個 forum 模組,其遷移檔案位於模組的 migrations 目錄中,我們可以使用以下命令

# migrate the migrations in a forum module non-interactively
yii migrate --migrationPath=@app/modules/forum/migrations --interactive=0

全域配置命令

您可以一次性地在應用程式配置中配置遷移命令,而無需每次執行遷移命令時都輸入相同的選項值,如下所示

return [
    'controllerMap' => [
        'migrate' => [
            'class' => 'yii\console\controllers\MigrateController',
            'migrationTable' => 'backend_migration',
        ],
    ],
];

透過以上配置,每次您執行遷移命令時,將會使用 backend_migration 資料表來記錄遷移歷史。您不再需要透過 migrationTable 命令列選項來指定它。

命名空間遷移

從 2.0.10 版本開始,您可以為遷移類別使用命名空間。您可以透過 migrationNamespaces 指定遷移命名空間的列表。使用遷移類別的命名空間允許您使用多個遷移來源位置。例如

return [
    'controllerMap' => [
        'migrate' => [
            'class' => 'yii\console\controllers\MigrateController',
            'migrationPath' => null, // disable non-namespaced migrations if app\migrations is listed below
            'migrationNamespaces' => [
                'app\migrations', // Common migrations for the whole application
                'module\migrations', // Migrations for the specific project's module
                'some\extension\migrations', // Migrations for the specific extension
            ],
        ],
    ],
];

注意: 從不同命名空間套用的遷移將會建立單一遷移歷史記錄,例如,您可能無法僅從特定命名空間套用或還原遷移。

在操作命名空間遷移時:建立新的、還原等等,您應該在遷移名稱之前指定完整的命名空間。請注意,反斜線 (\) 符號通常在 shell 中被視為特殊字元,因此您需要正確地跳脫它,以避免 shell 錯誤或不正確的行為。例如

yii migrate/create app\\migrations\\CreateUserTable

注意: 透過 migrationPath 指定的遷移不能包含命名空間,命名空間遷移只能透過 yii\console\controllers\MigrateController::$migrationNamespaces 屬性套用。

從 2.0.12 版本開始,migrationPath 屬性也接受陣列,用於指定多個包含無命名空間遷移的目錄。這主要是為了在現有專案中使用而新增的,這些專案使用來自不同位置的遷移。這些遷移主要來自外部來源,例如其他開發人員開發的 Yii 擴充套件,當開始使用新方法時,這些擴充套件無法輕易地更改為使用命名空間。

產生命名空間遷移

命名空間遷移遵循 "CamelCase" 命名模式 M<YYMMDDHHMMSS><Name> (例如 M190720100234CreateUserTable)。在產生此類遷移時,請記住資料表名稱將從 "CamelCase" 格式轉換為 "underscored" 格式。例如

yii migrate/create app\\migrations\\DropGreenHotelTable

在命名空間 app\migrations 中產生遷移,刪除資料表 green_hotel,並且

yii migrate/create app\\migrations\\CreateBANANATable

在命名空間 app\migrations 中產生遷移,建立資料表 b_a_n_a_n_a

如果資料表名稱是混合大小寫 (例如 studentsExam),您需要在名稱前面加上底線

yii migrate/create app\\migrations\\Create_studentsExamTable

這會在命名空間 app\migrations 中產生遷移,建立資料表 studentsExam

分離的遷移

有時,為所有專案遷移使用單一遷移歷史記錄並非理想的做法。例如:您可能會安裝一些 'blog' 擴充套件,其中包含完全分離的功能,並包含其自身的遷移,這些遷移不應影響專用於主要專案功能的遷移。

如果您希望將多個遷移完全彼此分離地套用和追蹤,您可以配置多個遷移命令,這些命令將使用不同的命名空間和遷移歷史記錄資料表

return [
    'controllerMap' => [
        // Common migrations for the whole application
        'migrate-app' => [
            'class' => 'yii\console\controllers\MigrateController',
            'migrationNamespaces' => ['app\migrations'],
            'migrationTable' => 'migration_app',
            'migrationPath' => null,
        ],
        // Migrations for the specific project's module
        'migrate-module' => [
            'class' => 'yii\console\controllers\MigrateController',
            'migrationNamespaces' => ['module\migrations'],
            'migrationTable' => 'migration_module',
            'migrationPath' => null,
        ],
        // Migrations for the specific extension
        'migrate-rbac' => [
            'class' => 'yii\console\controllers\MigrateController',
            'migrationPath' => '@yii/rbac/migrations',
            'migrationTable' => 'migration_rbac',
        ],
    ],
];

請注意,要同步資料庫,您現在需要執行多個命令,而不是一個命令

yii migrate-app
yii migrate-module
yii migrate-rbac

遷移多個資料庫

預設情況下,遷移會套用至由 db 應用程式元件 指定的相同資料庫。如果您希望將它們套用至不同的資料庫,您可以指定 db 命令列選項,如下所示

yii migrate --db=db2

上述命令會將遷移套用至 db2 資料庫。

有時可能會發生您想要將某些遷移套用至一個資料庫,而將其他遷移套用至另一個資料庫的情況。為了實現此目標,在實作遷移類別時,您應該明確指定遷移將使用的 DB 元件 ID,如下所示

<?php

use yii\db\Migration;

class m150101_185401_create_news_table extends Migration
{
    public function init()
    {
        $this->db = 'db2';
        parent::init();
    }
}

即使您透過 db 命令列選項指定了不同的資料庫,上述遷移仍將套用至 db2。請注意,遷移歷史記錄仍然會記錄在由 db 命令列選項指定的資料庫中。

如果您有多個遷移使用相同的資料庫,建議您建立一個包含上述 init() 程式碼的基礎遷移類別。然後,每個遷移類別都可以從這個基礎類別擴展。

提示: 除了設定 db 屬性之外,您還可以透過在遷移類別中建立與不同資料庫的新資料庫連線來操作不同的資料庫。然後,您可以使用 DAO 方法 以及這些連線來操作不同的資料庫。

您可以用於遷移多個資料庫的另一種策略是將不同資料庫的遷移保留在不同的遷移路徑中。然後,您可以使用不同的命令遷移這些資料庫,如下所示

yii migrate --migrationPath=@app/migrations/db1 --db=db1
yii migrate --migrationPath=@app/migrations/db2 --db=db2
...

第一個命令會將 @app/migrations/db1 中的遷移套用至 db1 資料庫,第二個命令會將 @app/migrations/db2 中的遷移套用至 db2,依此類推。

發現錯字或您認為此頁面需要改進嗎?
在 github 上編輯 !